package com.matrix.framework.sysconfig.token.service;

import com.matrix.framework.sysconfig.token.data.SysConfigPo;
import com.matrix.framework.sysconfig.token.data.SysConfigVo;
import com.matrix.framework.sysconfig.token.repositories.SysConfigRepository;
import com.matrix.framework.core.i18n.I18n;
import org.springframework.data.domain.PageRequest;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 系统配置服务
 * 
 * Copyright © 海平面工作室 版权所有
 *
 * @Author: Leo
 * @Create: 2025/06/23 23:25
 * @Since 1.2
 */
@Service
public class SysConfigService {

    private final SysConfigRepository sysConfigRepository;
    private final DatabaseClient databaseClient;

    public SysConfigService(SysConfigRepository sysConfigRepository, DatabaseClient databaseClient) {
        this.sysConfigRepository = sysConfigRepository;
        this.databaseClient = databaseClient;
    }

    /**
     * 分页查询系统配置
     */
    public Mono<Map<String, Object>> findAll(PageRequest pageable, String search, String sort) {
        StringBuilder baseQueryBuilder = new StringBuilder("SELECT * FROM sys_config WHERE 1=1");
        StringBuilder countQueryBuilder = new StringBuilder("SELECT COUNT(*) FROM sys_config WHERE 1=1");

        List<Object> values = new ArrayList<>();

        if (search != null && !search.isEmpty()) {
            baseQueryBuilder.append(" AND (`key` LIKE ? OR `value` LIKE ? OR memo LIKE ?)");
            countQueryBuilder.append(" AND (`key` LIKE ? OR `value` LIKE ? OR memo LIKE ?)");
            String searchPattern = "%" + search + "%";
            values.add(searchPattern);
            values.add(searchPattern);
            values.add(searchPattern);
        }

        if (sort != null && !sort.isEmpty()) {
            baseQueryBuilder.append(" AND sort = ?");
            countQueryBuilder.append(" AND sort = ?");
            values.add(sort);
        }

        baseQueryBuilder.append(" ORDER BY sort, `key`");
        if (pageable.isPaged()) {
            baseQueryBuilder.append(" LIMIT ").append(pageable.getPageSize())
                    .append(" OFFSET ").append(pageable.getOffset());
        }

        DatabaseClient.GenericExecuteSpec baseSpec = databaseClient.sql(baseQueryBuilder.toString());
        DatabaseClient.GenericExecuteSpec countSpec = databaseClient.sql(countQueryBuilder.toString());

        for (int i = 0; i < values.size(); i++) {
            baseSpec = baseSpec.bind(i, values.get(i));
            countSpec = countSpec.bind(i, values.get(i));
        }

        Flux<SysConfigVo> configs = baseSpec.map((row, metadata) -> {
            SysConfigVo config = new SysConfigVo();
            config.setSort(row.get("sort", String.class));
            config.setKey(row.get("key", String.class));
            config.setValue(row.get("value", String.class));
            config.setMemo(row.get("memo", String.class));
            return config;
        }).all();

        Mono<Long> total = countSpec.map((row, metadata) -> row.get(0, Long.class)).one();

        return configs.collectList()
                .flatMap(list -> total.map(count -> {
                    Map<String, Object> result = new HashMap<>();
                    result.put("items", list);
                    result.put("total", count);
                    return result;
                }));
    }

    /**
     * 查询所有配置
     */
    public Flux<SysConfigPo> findAll() {
        return sysConfigRepository.findAll();
    }

    /**
     * 根据配置键查询配置
     */
    public Mono<SysConfigPo> findByKey(String key) {
        return sysConfigRepository.findByKey(key);
    }

    /**
     * 根据配置分类查询配置
     */
    public Flux<SysConfigPo> findBySort(String sort) {
        return sysConfigRepository.findBySort(sort);
    }

    /**
     * 保存配置
     */
    public Mono<SysConfigPo> save(SysConfigPo sysConfig) {
        // 检查键是否已存在
        return sysConfigRepository.countByKey(sysConfig.getKey())
                .flatMap(count -> {
                    if (count > 0) {
                        // 存在则更新
                        return sysConfigRepository.updateByKey(sysConfig.getKey(), sysConfig.getValue(), sysConfig.getMemo())
                                .then(Mono.just(sysConfig));
                    } else {
                        // 不存在则新增
                        return sysConfigRepository.save(sysConfig);
                    }
                });
    }

    /**
     * 新增配置
     */
    public Mono<SysConfigPo> add(SysConfigPo sysConfig) {
        return sysConfigRepository.countByKey(sysConfig.getKey())
                .flatMap(count -> {
                    if (count > 0) {
                        return Mono.error(new RuntimeException(I18n.getMessage("config.key.exists")));
                    }
                    return sysConfigRepository.save(sysConfig);
                });
    }

    /**
     * 更新配置
     */
    public Mono<SysConfigPo> update(String key, SysConfigPo sysConfig) {
        return sysConfigRepository.findByKey(key)
                .switchIfEmpty(Mono.error(new RuntimeException(I18n.getMessage("config.not.exists"))))
                .flatMap(existing -> {
                    if (!key.equals(sysConfig.getKey())) {
                        // 如果要修改key，需检查新key是否已存在
                        return sysConfigRepository.countByKey(sysConfig.getKey())
                                .flatMap(count -> {
                                    if (count > 0) {
                                        return Mono.error(new RuntimeException(I18n.getMessage("config.key.exists")));
                                    }
                                    // 删除旧记录，插入新记录
                                    return sysConfigRepository.deleteByKey(key)
                                            .then(sysConfigRepository.save(sysConfig));
                                });
                    } else {
                        // 仅更新值
                        return sysConfigRepository.updateByKey(key, sysConfig.getValue(), sysConfig.getMemo())
                                .then(Mono.just(sysConfig));
                    }
                });
    }

    /**
     * 根据配置键删除配置
     */
    public Mono<Void> deleteByKey(String key) {
        return sysConfigRepository.deleteByKey(key);
    }

    /**
     * 根据配置分类和键删除配置
     */
    public Mono<Void> deleteBySortAndKey(String sort, String key) {
        return sysConfigRepository.deleteBySortAndKey(sort, key);
    }

    /**
     * 批量删除配置
     */
    public Mono<Void> deleteByKeys(List<String> keys) {
        return Flux.fromIterable(keys)
                .flatMap(this::deleteByKey)
                .then();
    }

    /**
     * 根据配置分类和键获取配置值
     */
    public Mono<String> getConfigValue(String sort, String key) {
        return sysConfigRepository.findBySortAndKey(sort, key)
                .map(SysConfigPo::getValue);
    }

    /**
     * 根据配置键获取配置值
     */
    public Mono<String> getConfigValue(String key) {
        return sysConfigRepository.findByKey(key)
                .map(SysConfigPo::getValue);
    }
} 